package service

import (
	"github.com/gin-gonic/gin"
	v1 "server_go/api/v1"
	"server_go/internal/model"
	"server_go/internal/repository"
)

type ArticleService interface {
	GetArticleById(req *v1.GetArticleProfileRequest) (*v1.GetArticleProfileResponse, error)
	GetArticleByTagId(req *v1.GetArticleByTagIdRequest) (*v1.GetArticleByTagIdResponse, error)
	GetArticleByUserId(req *v1.GetArticleByUserIdRequest) (*v1.GetArticleByUserIdResponse, error)
	AddArticle(req *v1.AddArticleRequest) error
	DeleteArticle(ctx *gin.Context, req *v1.DeleteArticleRequest) (*v1.DeleteArticleResponse, error)
	UpdateArticle(req *v1.UpdateArticleRequest) error
	GetAllArticle(req *v1.GetAllArticleRequest) (*v1.GetAllArticleResponse, error)
	GetAllArticleList(req *v1.GetAllArticleRequest) (*v1.GetAllArticleResponse, error)
	GetArticleByTitle(req *v1.GetArticleByTitleReq) (*v1.GetArticleByTitleResp, error)
}

func NewArticleService(
	service *Service,
	articleRepository repository.ArticleRepository,
	userRepo repository.UserRepository,
	tagRepo repository.TagRepository,
) ArticleService {
	return &articleService{
		Service:           service,
		articleRepository: articleRepository,
		userRepo:          userRepo,
		tagRepo:           tagRepo,
	}
}

type articleService struct {
	*Service
	articleRepository repository.ArticleRepository
	userRepo          repository.UserRepository
	tagRepo           repository.TagRepository
}

func (s *articleService) GetArticleById(req *v1.GetArticleProfileRequest) (*v1.GetArticleProfileResponse, error) {
	article, err := s.articleRepository.GetArticleById(req.ArticleId)
	if err != nil {
		return nil, err
	}
	author, err := s.userRepo.GetUserById(article.AuthorId)
	if err != nil {
		return nil, err
	}
	return &v1.GetArticleProfileResponse{
		ArticleId: int64(article.ID),
		Author:    author.Username,
		TagId:     article.TagId,
		Title:     article.Title,
		Describe:  article.Describe,
		Content:   article.MdContent,
		Type:      article.Type,
		Status:    article.Status,
		CreatedAt: article.CreatedAt,
		UpdatedAt: article.UpdatedAt,
		DeletedAt: article.DeletedAt,
	}, nil
}
func (s *articleService) GetArticleByTagId(req *v1.GetArticleByTagIdRequest) (*v1.GetArticleByTagIdResponse, error) {
	articles, total, err := s.articleRepository.GetArticleByTagId(req.TagId, req.Page, req.PageSize)
	if err != nil {
		return nil, err
	}
	authors := make([]*model.User, len(articles))
	for i, article := range articles {
		temp, err := s.userRepo.GetUserById(article.AuthorId)
		if err != nil {
			return nil, err
		}
		authors[i] = temp
	}
	resp := ConvertToGetArticleResponses(articles, authors)
	return &v1.GetArticleByTagIdResponse{Total: total, Record: resp}, nil
}
func (s *articleService) GetArticleByUserId(req *v1.GetArticleByUserIdRequest) (*v1.GetArticleByUserIdResponse, error) {
	articles, total, err := s.articleRepository.GetArticleByUserId(req.UserId, req.Page, req.PageSize)
	if err != nil {
		return nil, err
	}
	authors := make([]*model.User, len(articles))
	for i, article := range articles {
		temp, err := s.userRepo.GetUserById(article.AuthorId)
		if err != nil {
			return nil, err
		}
		authors[i] = temp
	}
	resp := ConvertToGetArticleResponses(articles, authors)
	return &v1.GetArticleByUserIdResponse{Total: total, Record: resp}, nil
}
func (s *articleService) AddArticle(req *v1.AddArticleRequest) error {
	if _, err := s.userRepo.GetUserById(req.AuthorId); err != nil {
		return err
	}
	if _, err := s.tagRepo.GetTagById(req.TagId); err != nil {
		return err
	}
	if err := s.articleRepository.AddArticle(&model.Article{
		AuthorId:  req.AuthorId,
		TagId:     req.TagId,
		Title:     req.Title,
		Describe:  req.Describe,
		MdContent: req.Content,
		Type:      req.Type,
		Status:    2,
	}); err != nil {
		return err
	}
	return nil
}
func (s *articleService) DeleteArticle(ctx *gin.Context, req *v1.DeleteArticleRequest) (*v1.DeleteArticleResponse, error) {
	if _, err := s.articleRepository.GetArticleById(req.ArticleId); err != nil {
		return nil, err
	}
	// todo:判断操作级别 管理员可以删除所有文章 但是用户只能删除自己的

	if err := s.articleRepository.DeleteArticle(req.ArticleId); err != nil {
		return nil, err
	}
	return &v1.DeleteArticleResponse{ArticleId: req.ArticleId}, nil
}
func (s *articleService) UpdateArticle(req *v1.UpdateArticleRequest) error {
	if _, err := s.articleRepository.GetArticleById(req.ArticleId); err != nil {
		return err
	}
	if err := s.articleRepository.UpdateArticle(req.ArticleId, &model.Article{
		TagId:     req.TagId,
		Title:     req.Title,
		Describe:  req.Describe,
		MdContent: req.Content,
		Status:    req.Status,
	}); err != nil {
		return err
	}
	return nil
}
func (s *articleService) GetAllArticle(req *v1.GetAllArticleRequest) (*v1.GetAllArticleResponse, error) {
	articles, total, err := s.articleRepository.GetAllArticle(req.Page, req.PageSize)
	if err != nil {
		return nil, err
	}
	authors := make([]*model.User, len(articles))
	for i, article := range articles {
		temp, err := s.userRepo.GetUserById(article.AuthorId)
		if err != nil {
			return nil, err
		}
		authors[i] = temp
	}
	resp := ConvertToGetArticleResponses(articles, authors)
	return &v1.GetAllArticleResponse{Total: total, Record: resp}, nil
}
func (s *articleService) GetAllArticleList(req *v1.GetAllArticleRequest) (*v1.GetAllArticleResponse, error) {
	articles, total, err := s.articleRepository.GetAllArticleList(req.Page, req.PageSize)
	if err != nil {
		return nil, err
	}
	authors := make([]*model.User, len(articles))
	for i, article := range articles {
		temp, err := s.userRepo.GetUserById(article.AuthorId)
		if err != nil {
			return nil, err
		}
		authors[i] = temp
	}
	resp := ConvertToGetArticleResponses(articles, authors)
	return &v1.GetAllArticleResponse{Total: total, Record: resp}, nil
}

func (s *articleService) GetArticleByTitle(req *v1.GetArticleByTitleReq) (*v1.GetArticleByTitleResp, error) {
	articles, total, err := s.articleRepository.GetArticleByTitle(req.Title, req.Page, req.PageSize)
	if err != nil {
		return nil, err
	}
	authors := make([]*model.User, len(articles))
	for i, article := range articles {
		temp, err := s.userRepo.GetUserById(article.AuthorId)
		if err != nil {
			return nil, err
		}
		authors[i] = temp
	}
	resp := ConvertToGetArticleResponses(articles, authors)
	return &v1.GetArticleByTitleResp{Total: total, Record: resp}, nil
}

// ConvertToGetUserResponses 函数功能： 将数据库中的User结构体转换为GetUserProfileResponse结构体
// 时间复杂度：O(n)
func ConvertToGetArticleResponses(articles []*model.Article, authors []*model.User) []v1.GetArticleProfileResponse {
	resp := make([]v1.GetArticleProfileResponse, len(articles))
	for i, article := range articles {
		var deletedAt interface{}
		if article.DeletedAt.Valid {
			deletedAt = article.DeletedAt.Time
		} else {
			deletedAt = nil
		}

		resp[i] = v1.GetArticleProfileResponse{
			ArticleId: int64(article.ID),
			Author:    authors[i].Username,
			TagId:     article.TagId,
			Title:     article.Title,
			Describe:  article.Describe,
			Content:   article.MdContent,
			Type:      article.Type,
			Status:    article.Status,
			CreatedAt: article.CreatedAt,
			UpdatedAt: article.UpdatedAt,
			DeletedAt: deletedAt,
		}
	}
	return resp
}
